package ru.reaperoq.routing

import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.routing.*
import ru.reaperoq.database.Database
import ru.reaperoq.dto.*
import ru.reaperoq.schema.UserRole
import ru.reaperoq.utils.getBody
import ru.reaperoq.utils.getUser
import ru.reaperoq.utils.withRole

fun Routing.computersRouting() {
    authenticate {
        route(URLS.Computers.COMPUTERS) {
            get {
                withRole(UserRole.ADMIN, UserRole.MODERATOR) {
                    call.respondSuccess(Database.computersService.readAll().map { computer ->
                        val createdBy = Database.userService.read(computer.createdBy) ?: run {
                            call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                            return@withRole
                        }
                        val verifiedBy = Database.userService.read(computer.verifiedBy) ?: run {
                            call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                            return@withRole
                        }
                        val components = Database.componentsService.readByComputer(computer.id).map { component ->
                            val componentCreatedBy = Database.userService.read(component.createdBy) ?: run {
                                call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                                return@withRole
                            }
                            val componentVerifiedBy = Database.userService.read(component.verifiedBy) ?: run {
                                call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                                return@withRole
                            }
                            ComponentResponse.from(
                                component,
                                UserResponse.from(componentCreatedBy),
                                UserResponse.from(componentVerifiedBy)
                            )
                        }
                        ComputerResponse.from(
                            computer,
                            UserResponse.from(createdBy),
                            UserResponse.from(verifiedBy),
                            components
                        )
                    })
                }
            }

            post {
                withRole(UserRole.ADMIN, UserRole.MODERATOR) {
                    val body = call.getBody<CreateComputerRequest>() ?: return@withRole
                    val user = getUser() ?: return@withRole
                    val id = Database.computersService.create(
                        body.serialNumber,
                        body.model,
                        body.manufacturer,
                        body.purchaseDate,
                        body.locationId,
                        body.notes,
                        user.id
                    )
                    call.respondSuccess(id)
                }
            }
        }

        get(URLS.Computers.MY) {
            val user = getUser() ?: return@get
            if (user.locationId == null) {
                call.respondError("Пользователь не привязан к локации", HttpStatusCode.BadRequest)
                return@get
            }
            call.respondSuccess(Database.computersService.readByLocation(user.locationId).map { computer ->
                val createdBy = Database.userService.read(computer.createdBy) ?: run {
                    call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                    return@get
                }
                val verifiedBy = Database.userService.read(computer.verifiedBy) ?: run {
                    call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                    return@get
                }
                val components = Database.componentsService.readByComputer(computer.id).map { component ->
                    val componentCreatedBy = Database.userService.read(component.createdBy) ?: run {
                        call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                        return@get
                    }
                    val componentVerifiedBy = Database.userService.read(component.verifiedBy) ?: run {
                        call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                        return@get
                    }
                    ComponentResponse.from(
                        component,
                        UserResponse.from(componentCreatedBy),
                        UserResponse.from(componentVerifiedBy)
                    )
                }
                ComputerResponse.from(
                    computer,
                    UserResponse.from(createdBy),
                    UserResponse.from(verifiedBy),
                    components
                )
            })
        }

        get(URLS.Computers.COMPUTER) {
            withRole(UserRole.ADMIN, UserRole.MODERATOR) {
                val id = call.parameters["id"]?.toIntOrNull() ?: run {
                    call.respondError("Неверный id", HttpStatusCode.BadRequest)
                    return@withRole
                }
                val computer = Database.computersService.read(id) ?: run {
                    call.respondError("Компьютер не найден", HttpStatusCode.NotFound)
                    return@withRole
                }
                val createdBy = Database.userService.read(computer.createdBy) ?: run {
                    call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                    return@withRole
                }
                val verifiedBy = Database.userService.read(computer.verifiedBy) ?: run {
                    call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                    return@withRole
                }
                val components = Database.componentsService.readByComputer(computer.id).map { component ->
                    val componentCreatedBy = Database.userService.read(component.createdBy) ?: run {
                        call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                        return@withRole
                    }
                    val componentVerifiedBy = Database.userService.read(component.verifiedBy) ?: run {
                        call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                        return@withRole
                    }
                    ComponentResponse.from(
                        component,
                        UserResponse.from(componentCreatedBy),
                        UserResponse.from(componentVerifiedBy)
                    )
                }
                call.respondSuccess(
                    ComputerResponse.from(
                        computer,
                        UserResponse.from(createdBy),
                        UserResponse.from(verifiedBy),
                        components
                    )
                )
            }
        }

        put(URLS.Computers.COMPUTER) {
            withRole(UserRole.ADMIN, UserRole.MODERATOR) {
                val id = call.parameters["id"]?.toIntOrNull() ?: run {
                    call.respondError("Неверный id", HttpStatusCode.BadRequest)
                    return@withRole
                }
                val body = call.getBody<CreateComputerRequest>() ?: return@withRole
                Database.computersService.update(
                    id,
                    body.model,
                    body.manufacturer,
                    body.purchaseDate,
                    body.locationId,
                    body.notes
                )
                call.respondSuccess(id)
            }
        }

        get(URLS.Computers.COMPUTERS_BY_LOCATION) {
            withRole(UserRole.ADMIN, UserRole.MODERATOR) {
                val id = call.parameters["id"]?.toIntOrNull() ?: run {
                    call.respondError("Неверный id", HttpStatusCode.BadRequest)
                    return@withRole
                }
                call.respondSuccess(Database.computersService.readByLocation(id).map { computer ->
                    val createdBy = Database.userService.read(computer.createdBy) ?: run {
                        call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                        return@withRole
                    }
                    val verifiedBy = Database.userService.read(computer.verifiedBy) ?: run {
                        call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                        return@withRole
                    }
                    val components = Database.componentsService.readByComputer(computer.id).map { component ->
                        val componentCreatedBy = Database.userService.read(component.createdBy) ?: run {
                            call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                            return@withRole
                        }
                        val componentVerifiedBy = Database.userService.read(component.verifiedBy) ?: run {
                            call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                            return@withRole
                        }
                        ComponentResponse.from(
                            component,
                            UserResponse.from(componentCreatedBy),
                            UserResponse.from(componentVerifiedBy)
                        )
                    }
                    ComputerResponse.from(
                        computer,
                        UserResponse.from(createdBy),
                        UserResponse.from(verifiedBy),
                        components
                    )
                })
            }
        }

        get(URLS.Computers.COMPUTER_BY_SERIAL) {
            val serial = call.parameters["serial"] ?: run {
                call.respondError("Не указан серийный номер", HttpStatusCode.BadRequest)
                return@get
            }
            val computer = Database.computersService.readBySerial(serial) ?: run {
                call.respondError("Компьютер не найден", HttpStatusCode.NotFound)
                return@get
            }
            val createdBy = Database.userService.read(computer.createdBy) ?: run {
                call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                return@get
            }
            val verifiedBy = Database.userService.read(computer.verifiedBy) ?: run {
                call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                return@get
            }
            val components = Database.componentsService.readByComputer(computer.id).map { component ->
                val componentCreatedBy = Database.userService.read(component.createdBy) ?: run {
                    call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                    return@get
                }
                val componentVerifiedBy = Database.userService.read(component.verifiedBy) ?: run {
                    call.respondError("Пользователь не найден", HttpStatusCode.NotFound)
                    return@get
                }
                ComponentResponse.from(
                    component,
                    UserResponse.from(componentCreatedBy),
                    UserResponse.from(componentVerifiedBy)
                )
            }
            call.respondSuccess(
                ComputerResponse.from(
                    computer,
                    UserResponse.from(createdBy),
                    UserResponse.from(verifiedBy),
                    components
                )
            )
        }

        patch(URLS.Computers.VERIFY) {
            val id = call.parameters["id"]?.toIntOrNull() ?: run {
                call.respondError("Неверный id", HttpStatusCode.BadRequest)
                return@patch
            }
            val user = getUser() ?: return@patch
            Database.computersService.verify(id, user.id)
            call.respondSuccess(id)
        }

        delete(URLS.Computers.COMPUTER) {
            withRole(UserRole.ADMIN, UserRole.MODERATOR) {
                val id = call.parameters["id"]?.toIntOrNull() ?: run {
                    call.respondError("Неверный id", HttpStatusCode.BadRequest)
                    return@withRole
                }
                Database.computersService.delete(id)
                call.respondSuccess("Компьютер удален")
            }
        }
    }
}